package com.kgo.jwt.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.kgo.jwt.entity.LoginEntity;

import java.util.*;

/**
 * @author keepgoon
 * @Description: TODO
 * @date 2019/3/18:47
 */
public class JWTTokenUtil {
    private static String Claim = "userName";
    private static String  secret = "secret";//token 密钥

    /**
     *
     * @param userName
     * @return
     */
    public static String getTokenWithClaim(String userName){
        try {
            //token 的加密部分，用于校验token的有效性，这里用密码作为校验因子
            Algorithm algorithm = Algorithm.HMAC256(secret);
            //创建token的时间，
            Date nowDate = new Date();
            //token 的有效时间
            Date expireDate = getAfterDate(nowDate,0,0,0,1,0,0);//2小过期
            //token的头部信息
            Map<String, Object> header_map = new HashMap<String, Object>();
            header_map.put("alg", "HS256");
            header_map.put("typ", "JWT");
            String token = JWT.create()
                    /*设置头部信息 Header*/
                    .withHeader(header_map)
                    /*设置 载荷 Payload*/
                    .withClaim(Claim, userName)
                    .withIssuer("SERVICE")//签名是有谁生成 例如 服务器
                    .withSubject("this is test token")//签名的主题
                    //.withNotBefore(new Date())//定义在什么时间之前，该jwt都是不可用的.
                    .withAudience("APP")//签名的观众 也可以理解谁接受签名的
                    .withIssuedAt(nowDate) //生成签名的时间
                    .withExpiresAt(expireDate)//签名过期的时间
                    /*签名 Signature */
                    .sign(algorithm);
            return token;
        } catch (JWTCreationException exception){
            exception.printStackTrace();
        }
        return null;
    }

    /**
     * 使用密码作为加密密钥
     * @param password
     * @param userName
     * @return
     */
    public static String getTokenWithClaim(String password ,String userName){
        try {
            //token 的加密部分，用于校验token的有效性，这里用密码作为校验因子
            Algorithm algorithm = Algorithm.HMAC256(password);
            //创建token的时间，
            Date nowDate = new Date();
            //token 的有效时间
            Date expireDate = getAfterDate(nowDate,0,0,0,1,0,0);//2小过期
            //token的头部信息
            Map<String, Object> header_map = new HashMap<String, Object>();
            header_map.put("alg", "HS256");
            header_map.put("typ", "JWT");
            String token = JWT.create()
                    /*设置头部信息 Header*/
                    .withHeader(header_map)
                    /*设置 载荷 Payload*/
                    .withClaim(Claim, userName)
                    .withIssuer("SERVICE")//签名是有谁生成 例如 服务器
                    .withSubject("this is test token")//签名的主题
                    //.withNotBefore(new Date())//定义在什么时间之前，该jwt都是不可用的.
                    .withAudience("APP")//签名的观众 也可以理解谁接受签名的
                    .withIssuedAt(nowDate) //生成签名的时间
                    .withExpiresAt(expireDate)//签名过期的时间
                    /*签名 Signature */
                    .sign(algorithm);
            return token;
        } catch (JWTCreationException exception){
            exception.printStackTrace();
        }
        return null;
    }
    public static Date getAfterDate(Date date, int year, int month, int day, int hour, int minute, int second){
        if(date == null){
            date = new Date();
        }
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        if(year != 0){
            cal.add(Calendar.YEAR, year);
        }
        if(month != 0){
            cal.add(Calendar.MONTH, month);
        }
        if(day != 0){
            cal.add(Calendar.DATE, day);
        }
        if(hour != 0){
            cal.add(Calendar.HOUR_OF_DAY, hour);
        }
        if(minute != 0){
            cal.add(Calendar.MINUTE, minute);
        }
        if(second != 0){
            cal.add(Calendar.SECOND, second);
        }
        return cal.getTime();
    }

    public static boolean verifyTokenWithPassword(String token,String password) {
        try {
            //校验因子
            Algorithm algorithm = Algorithm.HMAC256(password);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer("SERVICE")
                    .build(); //Reusable verifier instance
            System.out.println("校验 1 ");
            DecodedJWT jwt = verifier.verify(token);
            System.out.println("校验 2 ");
            String subject = jwt.getSubject();
            Map<String, Claim> claims = jwt.getClaims();
            System.out.println("校验 3 ");
            Claim claim = claims.get(Claim);
            System.out.println("校验 4 ");
            System.out.println(claim.asString());
            List<String> audience = jwt.getAudience();
            System.out.println(" " + subject);
            System.out.println(audience.get(0));
        } catch (JWTVerificationException exception){
            // exception.printStackTrace();
            System.out.println("校验失败 【 "+exception.getMessage() +"】");
            return false;
        }
        return true;
    }

    /**
     * JWT校验
     * @param token
     * @return
     */
    public static LoginEntity verifyToken(String token) {
        LoginEntity loginInfo = new LoginEntity();
        try {
            //校验因子
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer("SERVICE")
                    .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);
            String subject = jwt.getSubject();
            Map<String, Claim> claims = jwt.getClaims();
            Claim claim = claims.get(Claim);
            loginInfo.setUserName(claim.asString());
            loginInfo.setLogin(true);
            List<String> audience = jwt.getAudience();
        } catch (JWTVerificationException exception){
            // exception.printStackTrace();
            System.out.println("校验失败 【 "+exception.getMessage() +"】");
            LoginEntity failLogin = new LoginEntity();
            failLogin.setLogin(false);
            return failLogin;
        }
        return loginInfo;
    }





}
